/*----------------------------------------------------------
* FILE: BeanHelper.java
* LOGICAL NAME: BeanHelper
* PRODUCT: bila-framework
*----------------------------------------------------------
* MODIFICATIONS
* DATE Aug 31, 2011
* AUTHOR wjuarez
*----------------------------------------------------------
*/

package bila.framework.commons;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.springframework.beans.BeanUtils;

/**
 * @author WJuarez
 * <b>Created by </b>wjuarez
 * <b>for</b> bila-framework
 * <b>package</b> bila.framework.commons
 * <b>on</b> Aug 31, 2011 9:58:25 PM
 * <b>Purpose</b> 
 * <p>
 *		Metodos auxiliares para el manejo de beans
 *		y con la informacion que posee
 * </p>
 */
public class BeanHelper extends org.springframework.beans.BeanUtils{

	public static final String SET = "set";
	public static final String GET = "get";
	public static final String GETCLASS = "getClass";
	
	/**
	 * Recupera los nombres de los atributos del objeto
	 * retomandolos de los metodos get
	 * @param object objeto del cual se desea recuperar
	 * los nombres de los atributos
	 * @return objeto de tipo List<String> con los nombres de los atributos del objeto
	 */
	public static List<String> getGetterName(Object object){
		//Recupero los metodos del objeto
		Method[] methods = object.getClass().getMethods();
		List<String> list = new ArrayList<String>();
		
		for(int i=0; i < methods.length; i++){
			Method method = methods[i];
			//Verifico si el objeto es getter y lo agrego a la lista
			if(isGetter(method.getName()) && !method.getName().equals(GETCLASS))
				list.add(method.getName());
		}
		return list;
	}
	
	/**
	 * Ejecuta todos los metodos get del objeto que se pasa de parametro
	 * y recupera el valor de aquellos que no son nulos para guardarlo
	 * en una lista
	 * @param object objeto del cual se recupera los valores de sus atributos
	 * @return objeto de tipo List<Object>
	 */
	public static List<Object> getGetterValue(Object object){
		List<Object> list = new ArrayList<Object>();
		
		//Recupero los metodos del objeto
		Method[] methods = object.getClass().getMethods();
		String name = "";
		for(int i=0; i < methods.length; i++){
			Method method = methods[i];
			try {
				if(isGetter(method.getName()) && !method.getName().equals(GETCLASS)){
					name = method.getName().substring(3, method.getName().length());
					name = name.substring(0, 1).toLowerCase() + name.substring(1);
					list.add(name + "##" + method.invoke(object, null));
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
	
	/**
	 * Verifica si el metodo que se pasa como parametro es un accesor get
	 * @param methodName metodo que se desea verificar
	 * @return true de ser cierto y false en caso contrario
	 */
	public static boolean isGetter(String methodName){
		return methodName.startsWith(GET);
	}
	
	/**
	 * Verifica si el metodo que se pasa como parametro es un accesor set
	 * @param methodName metodo que se desea verificar
	 * @return true de ser cierto y false en caso contrario
	 */
	public boolean isSetter(String methodName){
		return methodName.startsWith(SET);
	}
	
	/**
	 * Copia las propiedades del objeto source al objeto target, siempre y cuando
	 * estas posean el mismo nombre y el mismo tipo
	 * @param source objeto fuente
	 * @param target objeto donde se copiara las propiedades
	 * @param excludes atributos que se desean excluir
	 */
	public static void copyAttributes(Object source, Object target, String[] excludes){
		BeanUtils.copyProperties(source, target, excludes);
	}
	
	/**
	 * Setea a nullo los atributos que posean cadenas vacias o ceros
	 * @param obj objeto que se desea modificar
	 */
	@SuppressWarnings("rawtypes")
	public static void setEmptyStringsAndZeroNumbersToNull(Object obj){
		try {
			Map map = getProperties(obj);
			//Map map =  BeanUtils.describe(obj);
			
			for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
				String key = (String) iter.next();
				
				Object value = map.get(key);
				if (value instanceof String) {
					if(GeneralFunction.isNullOrEmpty(value)){
						setProperty(obj, key, null);
					}					
				}//instance
				
				if(value instanceof Number){
					Number num = (Number)value;
					if(num.doubleValue() == 0){
						setProperty(obj, key, null);
						//BeanUtils.setProperty(obj, key, null);
					}// val=0						
				}//instance
				
			}//for keySet			
		} catch (Exception e) {
			//log.error("exception while setting empty strings to null");
			throw new RuntimeException(e);
		}		
	}
	
	private static void setProperty(Object bean, String name, Object value)
			throws IllegalAccessException, InvocationTargetException {
		BeanUtilsBean.getInstance().setProperty(bean, name, value);
	}
	
	private static String getPropertyForBeanProp(String getterName){
		try{
			String noGet = getterName.substring(3);
			String init = noGet.substring(0,1).toLowerCase();
			String end = noGet.substring(1);
			return init + end;
		}catch(Exception e){
			return null;
		}	
	}

	@SuppressWarnings("rawtypes")
	private static Map getProperties(Object bean){
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Method[] methods = bean.getClass().getMethods();
			Object value = null;
			String methodStr = null;
			
			for(int i =0; i<methods.length; i++){
				if( !isGetter(methods[i].getName()) ){					
					continue;
				}
					
				methodStr = getPropertyForBeanProp(methods[i].getName());
				value = methods[i].invoke(bean, (Object[])null);
				map.put(methodStr, value);
			}
			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return map;
		
	}//getProperties
	
}//class
